package servlet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import server.WebServer;

public class MyRequest {
	private String method;
	private String requestResource;
	private String HTTPVersion;
	private HashMap<String,String> HTTPHeaders = new HashMap<String,String>();
	private List<String> HeaderNames = new ArrayList<String>();
	private String projectName;
	private String requestResourceName;
	private String requestResourcePath;
	private Map<String,List<String>> parameterMap = new HashMap<String,List<String>>();
	private List<String> paraNames = new ArrayList<String>();
	private HashMap<String,Object> attributes = new HashMap<String,Object>();
	private MyCookie[] cookies;
	private String requestResourceType;
	private String extensionName;
	private HashMap<String,MySession> sessionContainer;
	private MyResponse response;
	
	public MyResponse getResponse() {
		return response;
	}

	public void setResponse(MyResponse response) {
		this.response = response;
	}

	public String getProjectName() {
		return projectName;
	}
	
	public String getHTTPVersion() {
		return HTTPVersion;
	}

	public String getRequestResource() {
		return requestResource;
	}
	
	public String getMethod() {
		return method;
	}
	
	public String getHeaderByName(String name){
		return HTTPHeaders.get(name);
	}
	
	public List<String> getHeaderNames() {
		return HeaderNames;
	}
	
	public String getParameter(String name){
		
		return parameterMap.get(name).get(0);
	}
	
	public Object getAttribute(String name){
		return attributes.get(name);
	}
	
	public String getRequestResourceName() {
		return requestResourceName;
	}

	public String getRequestResourcePath() {
		return requestResourcePath;
	}
	
	public MySession getMySession(){
		return getMySession(true);
	}
	public MyCookie[] getMyCookies(){
		return cookies;
	}
	
	public String getExtensionName() {
		return extensionName;
	}
	
	public String getRequestResourceType() {
		return requestResourceType;
	}
	
	public Map<String, List<String>> getParameterMap() {
		return parameterMap;
	}


	public MyRequest(InputStream inputStream) {
		String postParaLine = "";
		this.sessionContainer = WebServer.getServerContext().getSessionContainer();
		
		BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
		try {
			//解析请求行，【方法】，【请求资源】，【HTTP版本】
			String requestLine = in.readLine();
			String[] requestLineTokens = requestLine.split(" ");
			method = requestLineTokens[0];
			requestResource = requestLineTokens[1];
			HTTPVersion = requestLineTokens[2];
			
			//解析请求资源，【资源路径】，【项目名】，【资源名称】			
			int second = requestResource.indexOf("/", 1);
			if(second!=-1){
				projectName = requestResource.substring(1, second);				
			}
			else{
				projectName = "";
			}
			//资源名称是指文件名+扩展名；资源路径是指请求资源全路径+资源名，不包含GET参数			
			if(requestResource.contains("?")){
				requestResourceName = requestResource.substring(requestResource.lastIndexOf("/")+1, requestResource.indexOf("?"));
				requestResourcePath = requestResource.substring(0,requestResource.indexOf("?"));
			}
			else{
				requestResourceName = requestResource.substring(requestResource.lastIndexOf("/")+1);
				requestResourcePath = requestResource;
			}
			//解析【请求资源类型】，（扩展名）
			String extensionName;
			if(requestResourceName.contains(".")){
				extensionName = requestResourceName.substring(requestResourceName.indexOf(".")+1);
			}
			else{
				extensionName = "";
			}
			this.extensionName = extensionName;
			
			//根据扩展名区分请求资源的类型
			if(extensionName.equals("do")){
				requestResourceType = "servlet";
			}
			else if(extensionName.equals("jsp")){
				requestResourceType = "jsp";
			}
			else{
				requestResourceType = "static";
			}
			//解析HTTP头属性
			String line = null; 
			while((line=in.readLine())!=null&&!line.equals("")){
				String headerName = line.substring(0, line.indexOf(":")).trim();
				String headerBody = line.substring(line.indexOf(":")+1, line.length()).trim();
				HeaderNames.add(headerName);
				//将解析出的HTTPHeader存入HashMap，后面可以按名称取出报文头属性
				HTTPHeaders.put(headerName, headerBody);
			}
			if(method.equals("POST")){
				//POST方式下，读取报文体
				int postLength = Integer.valueOf(this.HTTPHeaders.get("Content-Length"));
				char[] postData = new char[postLength];
				in.read(postData);
				postParaLine = new String(postData);	
				
			}
			//解析Cookie
			String cookieString = HTTPHeaders.get("Cookie");
			if(cookieString!=null){
				String[] tokens = cookieString.split(";");
				cookies = new MyCookie[tokens.length];
				for(int i=0;i<tokens.length;i++){
					String token = tokens[i];
					String cookieName = token.substring(0, token.indexOf("=")).trim();
					String cookieValue =  token.substring(token.indexOf("=")+1, token.length()).trim();
					MyCookie cookie = new MyCookie(cookieName,cookieValue);
					cookies[i] = cookie;
				}
			}
			//解析变量GET-Parameter

				if(requestResource.contains("?")){
					String paraLine = requestResource.substring(requestResource.indexOf("?")+1);
					String[] tokens;
					if(paraLine.contains("&")){
						tokens = paraLine.split("&");
					}
					else{
						tokens = new String[1];
						tokens[0] = paraLine;
					}
					for(String token : tokens){
						String paraName = token.substring(0, token.indexOf("=")).trim();
						String paraValue = token.substring(token.indexOf("=")+1, token.length()).trim();
						if(!paraNames.contains(paraName)){
							paraNames.add(paraName);
							List<String> paraValueList = new ArrayList<String>();
							paraValueList.add(paraValue);
							parameterMap.put(paraName, paraValueList);
							
						}
						else{
							parameterMap.get(paraName).add(paraValue);
						}
						
					}
				}

			//解析变量POST-Parameter
			if(this.method.equals("POST")&&postParaLine!=null&&!postParaLine.equals("")){
				String[] tokens;
				if(postParaLine.contains("&")){
					tokens = postParaLine.split("&");
				}
				else{
					tokens = new String[1];
					tokens[0] = postParaLine;
				}
				for(String token : tokens){
					String paraName = token.substring(0, token.indexOf("=")).trim();
					String paraValue = token.substring(token.indexOf("=")+1, token.length()).trim();
					if(!paraNames.contains(paraName)){
						paraNames.add(paraName);
						List<String> paraValueList = new ArrayList<String>();
						paraValueList.add(paraValue);
						parameterMap.put(paraName, paraValueList);
						
					}
					else{
						parameterMap.get(paraName).add(paraValue);
					}
					
				}
			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public MySession getMySession(boolean create){
		String MySessionId = null;
		MyCookie[] cookies =  getMyCookies();
		if(cookies!=null){
			for(MyCookie cookie : cookies){
				if(cookie.getName().equals("MySessionId")){
					MySessionId = cookie.getValue();
				}
			}
		}
		MySession session = null;
		if(create){
	
			if(MySessionId!=null){
				if(sessionContainer.get(MySessionId)==null){
					
					session = new MySession(MySessionId);
				}
				else{
					
					session = (MySession)sessionContainer.get(MySessionId);
				}
				
			}
			else{
				UUID uuid = UUID.randomUUID();
				String sessionId = uuid.toString().replace("-", "");
				session = new MySession(sessionId);
				sessionContainer.put(sessionId, session);
				MyCookie cookie = new MyCookie("MySessionId",sessionId);
				response.addCookie(cookie);
			}
		}
		else{
			
			session = (MySession)sessionContainer.get(MySessionId);
		}
		return session;
	}
	
	public String[] getParaValues(String name){
		if(this.parameterMap.get(name)!=null){
			List<String> aa = this.parameterMap.get(name);
			String[] ret = new String[aa.size()];
			for(int i=0;i<aa.size();i++){
				ret[i] = aa.get(i);
			}
			return ret;
		}
		else{
			return null;
		}
	}

}
